/*
    Author: Christopher Diggins
    License: MIT Licence 1.0
    Website: http://www.cdiggins.com
*/

namespace cvm
{
	struct Any;

	void TypeError(PChar x) {
		throw 1;
	}
	
	struct BaseType
	{
		// These are reference counting methods used by reference types
		virtual void IncRef(Any& a) { }
		virtual void DecRef(Any& a) { }
		virtual int RefCnt(Any& a) { return -1; }

		// Type information
		virtual PChar TypeName() { return "BaseType"; }
		virtual bool IsRefType() { return false; }
		
		// Misc function
		virtual void Write(Any& x, Any& y) { printf("???"); }

		virtual int ToInt(Any& a);
		virtual bool ToBool(Any& a);
		virtual char ToChar(Any& a);
		virtual PChar ToPChar(Any& a);
		virtual double ToDbl(Any& a);
		virtual FILE* ToFile(Any& a);
	};

	template<typename Interface_T> 
	struct ValType : Interface_T
	{
	};

	template<typename Interface_T, typename Object_T>
	struct RefType : Interface_T
	{
		struct Holder {
			Holder(Object_T* o) 
				: object(o), refcnt(1)
			{ }
			Impl() 
				: refcnt(1)
			{ }
			int refcnt;
			Object_T* object;
		};

		void Initialize(Object_T& o, Any& result) {
			SetImplPtr(result, new Impl(o));
			// NOTE: 
		}

		Impl* GetImplPtr(Any& any) {
			Impl* p = reinterpret_cast<Impl*>(any.data.vp);
			assert(p != NULL);
			return p;
		}

		void SetImplPtr(Any& any, Impl* x) {
			reinterpret_cast<Impl*>(any.data.vp) = x;
		}

		Object_T* GetObjectPtr(Any& any) { 
			return GetImplPtr(any)->object;
		}

		void IncRef(Any& any) {
			GetImplPtr(any)->refcnt++;
		}

		void DecRef(Any& any) {
			int& n = GetImplPtr(any)->refcnt;
			assert(n > 0);
			--n;
			if (n == 0) {
				Finalize(any);			
				delete GetImplPtr(any);
				any.data.vp = NULL;
			}
		}		

		virtual void Finalize(Any& any) {
			// By default does nothing.
			// override to provide custom 
			// behavior on deletion.
		}
		
		void Write(Any& x, Any& y) { 
			fprintf(y.ToFile(), "%p:%d", GetImplPtr(x)); 
		} 
	};

}